# -*- coding: utf-8 -*-
"""
@Author: Logan
@Date:   2025/7/11 16:38
@Description:
数据存储方式：
使用 Redis 的 哈希表（hash） 存储测试进度（总用例数、成功数、时间等），键为 ui_autotest_process。
使用 Redis 的 列表（list） 存储失败用例名称，键为 failed_testcase_names，方便按顺序查看。
使用流程：
测试开始前：调用 reset_all() 清空历史数据 → init_process(总用例数) 初始化进度。
测试过程中：每个用例执行成功调用 update_success()，失败调用 update_fail() 和 insert_into_fail_testcase_names(用例名)。
测试结束后：调用 write_end_time() 记录结束时间。
查看结果：通过 get_process() 看进度百分比，get_result() 看统计数据，get_fail_testcase_names() 看失败用例。
"""

from common.tools import get_now_time
from common.redis_operation import RedisOperation


class Process:
    """
    测试进度跟踪类：用于记录和管理UI自动化测试的进度、结果和失败用例信息
    数据存储在Redis中，支持初始化进度、更新用例结果、查询进度等功能
    """

    def __init__(self):
        """初始化Redis连接和常量（Redis中的键名）"""
        # 获取Redis客户端实例（从RedisOperation类中获取已连接的客户端）
        self.redis_client = RedisOperation().redis_client

        # 定义Redis中存储数据的键名（避免硬编码，方便统一修改）
        self.UI_AUTOTEST_PROCESS = "ui_autotest_process"  # 哈希表：存储测试总进度数据
        self.FAILED_TESTCASE_NAMES = "failed_testcase_names"  # 列表：存储失败用例名称

    def reset_all(self):
        """重置所有测试进度数据（清空Redis中存储的历史记录）"""
        # 删除哈希表（包含总进度、成功数、失败数等）
        self.redis_client.delete(self.UI_AUTOTEST_PROCESS)
        # 删除列表（包含所有失败用例名称）
        self.redis_client.delete(self.FAILED_TESTCASE_NAMES)

    def init_process(self, total):
        """
        初始化测试进度数据（测试开始前调用）
        :param total: 测试用例的总数量（整数）
        """
        # 使用Redis哈希表（hash）存储进度数据，键为"ui_autotest_process"
        # hset(key, field, value)：向哈希表中添加字段和值
        self.redis_client.hset(self.UI_AUTOTEST_PROCESS, "total", total)  # 总用例数
        self.redis_client.hset(self.UI_AUTOTEST_PROCESS, "success", 0)  # 成功用例数（初始为0）
        self.redis_client.hset(self.UI_AUTOTEST_PROCESS, "fail", 0)  # 失败用例数（初始为0）
        self.redis_client.hset(self.UI_AUTOTEST_PROCESS, "start_time", get_now_time())  # 测试开始时间
        self.redis_client.hset(self.UI_AUTOTEST_PROCESS, "end_time", "")  # 测试结束时间（初始为空）

    def update_success(self):
        """成功执行一个测试用例后调用，将成功数+1"""
        # hincrby(key, field, increment)：哈希表字段值自增（默认+1）
        self.redis_client.hincrby(self.UI_AUTOTEST_PROCESS, "success")

    def update_fail(self):
        """一个测试用例执行失败后调用，将失败数+1"""
        self.redis_client.hincrby(self.UI_AUTOTEST_PROCESS, "fail")

    def insert_into_fail_testcase_names(self, fail_testcase_name):
        """
        记录失败的测试用例名称（失败后调用）
        :param fail_testcase_name: 失败的用例名称（字符串）
        """
        # lpush(key, value)：向列表左侧添加元素（最新失败的用例在最前面）
        self.redis_client.lpush(self.FAILED_TESTCASE_NAMES, fail_testcase_name)

    def get_process(self):
        """
        获取当前测试进度百分比（已执行用例数/总用例数）
        :return: 进度百分比字符串（如"50.0%"）
        """
        # 调用get_result()获取总用例数、成功数、失败数
        total, success, fail, _ = self.get_result()
        # 转换为整数（避免字符串计算错误）
        total = int(total)
        success = int(success)
        fail = int(fail)

        if total == 0:
            # 总用例数为0时，进度为0%
            return "0%"
        else:
            # 计算进度：(已执行数/总数)×100%，保留1位小数
            progress = (success + fail) / total * 100
            return f"{progress:.1f}%"  # 格式化字符串（如50.0%）

    def get_result(self):
        """
        获取测试结果统计数据
        :return: 元组 (总用例数, 成功数, 失败数, 开始时间)
        """
        # hget(key, field)：获取哈希表中指定字段的值
        # 若字段不存在（如未初始化），返回None，用or 0设置默认值
        total = self.redis_client.hget(self.UI_AUTOTEST_PROCESS, "total") or 0
        success = self.redis_client.hget(self.UI_AUTOTEST_PROCESS, "success") or 0
        fail = self.redis_client.hget(self.UI_AUTOTEST_PROCESS, "fail") or 0
        start_time = self.redis_client.hget(self.UI_AUTOTEST_PROCESS, "start_time") or "-"  # 默认显示"-"

        # 转换为整数（因为Redis存储的是字符串，需转为数字才能计算）
        return int(total), int(success), int(fail), start_time

    def get_fail_testcase_names(self):
        """
        获取所有失败的测试用例名称列表
        :return: 列表（包含所有失败用例名称）
        """
        # lrange(key, start, end)：获取列表中指定范围的元素，0到-1表示所有元素
        return self.redis_client.lrange(self.FAILED_TESTCASE_NAMES, 0, -1)

    def write_end_time(self):
        """测试全部结束后调用，记录结束时间"""
        self.redis_client.hset(self.UI_AUTOTEST_PROCESS, "end_time", get_now_time())
